import json
from .models import SQLConfig
from .tools import execute_sql
from .llm_service import LLMService

class MyAgent:
    def __init__(self):
        self.llm = LLMService()
        self.max_steps = 5  # 设置最大执行步骤，防止无限循环

    def _get_available_tools_prompt(self):
        tools_description = "你拥有以下可以调用的工具（能力）：\n"
        for view in SQLConfig.objects.all():
            tools_description += (
                f"- 工具名称: `{view.name}`\n"
                f"  - 功能描述: {view.description}\n"
                f"  - 需要参数: {json.dumps(view.params, ensure_ascii=False)}\n\n"
            )
        return tools_description

    def run(self, user_instruction: str) -> str:
        # 初始化对话历史和思考过程
        conversation_history = [f"用户的初始指令是: '{user_instruction}'"]
        
        for step in range(self.max_steps):
            print(f"--- Agent Step {step + 1} ---")

            # ---- 步骤1: 思考并规划下一步行动 ----
            planner_prompt = f"""
            你是一个专业的养老数据助手，可以查询老人服务数据。同时你是还是一个多步骤任务规划专家。
            你的目标是根据用户的指令和当前的对话历史，决定下一步是调用一至多个工具，还是已经可以总结并回答问题了。

            {self._get_available_tools_prompt()}

            当前的对话历史和已执行步骤如下:
            ---
            {''.join(conversation_history)}
            ---

            现在，请思考并决策。你的输出必须是以下两种JSON格式之一：

            1. 如果你认为还需要调用工具来获取更多信息，请输出：
            {{
              "thought": "我还需要xx信息，所以我需要调用xx工具。",
              "action": {{
                "type": "tool_call",
                "tools": [
                  {{
                    "tool_name": "要调用的第一个工具名称",
                    "parameters": {{ "参数1": "值1" }}
                  }},
                  {{
                    "tool_name": "要调用的第二个工具名称",
                    "parameters": {{ "参数A": "值A" }}
                  }}
              }}
            }}

            2. 如果你认为已经有足够的信息来回答用户的问题，请输出：
            {{
              "thought": "我已经获取了所有必要的信息，现在可以进行总结了。",
              "action": {{
                "type": "finish",
                "summary": "在这里生成对用户问题的最终回答。"
              }}
            }}
            """
            
            llm_response_str = self.llm.invoke(planner_prompt)
            try:
                plan = json.loads(llm_response_str)
                thought = plan.get("thought", "")
                action = plan.get("action", {})
                action_type = action.get("type") 
            except (json.JSONDecodeError, AttributeError):
                return "对不起，我的思考过程出错了，请稍后再试。"
            
            # 将LLM的思考过程加入历史记录
            conversation_history.append(f"\n思考: {thought}\n")

            # ---- 步骤2: 判断并执行 ----
            if action_type == "finish":
                # 任务完成，返回最终总结
                summary = action.get("summary", "任务已完成，但没有生成总结。")
                print(f"Agent决定完成任务。总结: {summary}")
                return summary

            elif action_type == "tool_call":
                # 获取工具调用列表
                tool_calls = action.get("tools", [])
                print(f"Agent决定调用工具: {tool_calls}")
                if not isinstance(tool_calls, list) or not tool_calls:
                    return "对不起，我决定调用工具，但没有找到具体的工具列表。"

                # 循环执行所有工具调用，并收集结果
                observations = []
                for tool_call in tool_calls:
                    tool_name = tool_call.get("tool_name")
                    parameters = tool_call.get("parameters", {})

                    if not tool_name:
                        continue # 如果某个工具信息不完整，则跳过

                    # print(f"Agent决定调用工具: {tool_name} with params {parameters}")
                    tool_result = execute_sql(tool_name, parameters)
                    
                    # 将单个工具的执行结果格式化为观察记录
                    observation = f"工具 '{tool_name}' 的执行结果是:\n{json.dumps(tool_result, ensure_ascii=False, indent=2)}\n"
                    observations.append(observation)
                
                # 将本步骤所有工具的观察结果合并，并加入历史记录
                full_observation = "".join(observations)
                conversation_history.append(full_observation)
                print(full_observation)

            else:
                return "对不起，我不知道下一步该做什么（收到了未知的行动类型）。"

        return "任务执行步骤已达上限，但仍未完成。请尝试简化您的问题。"